const EventEmitter = require("events");
const EnhancedModbusClient = require("./enhancedModbusClient");

/**
 * Modbus通信管理器
 * 封装了与PLC的Modbus通信逻辑
 */
class ModbusCommunicationManager extends EventEmitter {
  constructor(ip, port) {
    super();
    this.client = new EnhancedModbusClient(ip, port);
    this.isConnected = false;
    this._setupClientEvents();
  }

  /**
   * 设置客户端事件转发
   * @private
   */
  _setupClientEvents() {
    if (!this.client) return;

    // 转发所有客户端事件到当前实例
    this.client.on("error", (err) => {
      this.isConnected = false;
      this.emit("error", err);
    });
    this.client.on("disconnect", () => {
      this.isConnected = false;
      this.emit("disconnect");
    });
    this.client.on("connectFailed", (err) => {
      this.isConnected = false;
      this.emit("connectFailed", err);
    });
    this.client.on("timeout", () => {
      this.emit("timeout");
    });
    this.client.on("connect", () => {
      this.isConnected = true;
      this.emit("connect");
    });
    this.client.on("maxReconnects", () => {
      this.isConnected = false;
      this.emit("maxReconnects");
    });
    this.client.on("destroy", () => {
      this.isConnected = false;
      this.emit("destroy");
    });
  }

  /**
   * 连接到PLC
   * @returns {Promise<boolean>} 连接是否成功
   */
  async connect() {
    try {
      const result = await this.client.connect();
      if (result) {
        this.isConnected = true;
        console.log(`成功连接到PLC: ${this.client.ip}:${this.client.port}`);
        this.emit("connect");
        // 连接成功后等待PLC完全准备好
        await new Promise((resolve) => setTimeout(resolve, 2000));
        return true;
      } else {
        this.isConnected = false;
        const error = new Error("连接PLC失败");
        this.emit("connectFailed", error);
        return false;
      }
    } catch (err) {
      console.error("连接PLC失败:", err.message);
      this.isConnected = false;
      this.emit("connectFailed", err);
      return false;
    }
  }

  /**
   * 断开连接
   */
  disconnect() {
    try {
      this.client.destroy();
      this.isConnected = false;
      console.log("已断开与PLC的连接");
    } catch (err) {
      console.error("断开连接时出错:", err.message);
    }
  }

  /**
   * 读取输入寄存器
   * @param {number} startAddress - 起始地址
   * @param {number} quantity - 读取数量
   * @returns {Promise<array>} 读取到的数据
   */
  async readInputRegisters(startAddress, quantity) {
    if (!this.isConnected) {
      throw new Error("未连接到PLC");
    }

    try {
      return await this.client.readInputRegisters(startAddress, quantity);
    } catch (err) {
      // 如果是连接错误，更新连接状态
      if (this._isConnectionError(err)) {
        this.isConnected = false;
      }
      throw err;
    }
  }

  /**
   * 读取保持寄存器
   * @param {number} startAddress - 起始地址
   * @param {number} quantity - 读取数量
   * @returns {Promise<array>} 读取到的数据
   */
  async readHoldingRegisters(startAddress, quantity) {
    if (!this.isConnected) {
      throw new Error("未连接到PLC");
    }

    try {
      return await this.client.readHoldingRegisters(startAddress, quantity);
    } catch (err) {
      // 如果是连接错误，更新连接状态
      if (this._isConnectionError(err)) {
        this.isConnected = false;
      }
      throw err;
    }
  }

  /**
   * 判断是否为连接相关错误
   * @param {Error} err - 错误对象
   * @returns {boolean} 是否为连接相关错误
   */
  _isConnectionError(err) {
    const message = err.message || "";
    return (
      message.includes("Port Not Open") ||
      message.includes("Client is not connected") ||
      message.includes("ETIMEDOUT") ||
      message.includes("TCP Connection Timed Out") ||
      (err.code &&
        (err.code === "ECONNRESET" ||
          err.code === "ECONNREFUSED" ||
          err.code === "ENOTFOUND" ||
          err.code === "EHOSTUNREACH"))
    );
  }

  /**
   * 写入单个寄存器数组
   * @param {number} address - 起始寄存器地址
   * @param {array} values - 要写入的值数组
   * @returns {Promise<object>} 写入结果
   */
  async writeSingleRegisterArray(address, values) {
    if (!this.isConnected) {
      throw new Error("未连接到PLC");
    }

    try {
      return await this.client.writeSingleRegisterArray(address, values);
    } catch (err) {
      // 如果是连接错误，更新连接状态
      if (this._isConnectionError(err)) {
        this.isConnected = false;
      }
      throw err;
    }
  }

  /**
   * 写入32位浮点数数组到指定地址
   * @param {number} startAddress - 起始地址
   * @param {number[]} values - 要写入的数值数组
   * @returns {Promise<boolean>} 写入是否成功
   */
  async write32BitFloats(startAddress, values) {
    if (!this.isConnected) {
      throw new Error("未连接到PLC");
    }

    try {
      return await this.client.write32BitFloats(startAddress, values);
    } catch (err) {
      // 如果是连接错误，更新连接状态
      if (this._isConnectionError(err)) {
        this.isConnected = false;
      }
      throw err;
    }
  }

  /**
   * 批量写入多个寄存器数组
   * @param {array} writeArrayRequests - 写入请求数组 [{address, values}, ...]
   * @returns {Promise<object>} 批量写入结果
   */
  async writeMultipleRegisterArrays(writeArrayRequests) {
    if (!this.isConnected) {
      throw new Error("未连接到PLC");
    }

    try {
      return await this.client.writeMultipleRegisterArrays(writeArrayRequests);
    } catch (err) {
      // 如果是连接错误，更新连接状态
      if (this._isConnectionError(err)) {
        this.isConnected = false;
      }
      throw err;
    }
  }

  /**
   * 写入保持寄存器（兼容旧接口）
   * @param {number} address - 寄存器地址
   * @param {number|array} value - 要写入的值或值数组
   * @returns {Promise<object>} 写入结果
   */
  async writeHoldingRegister(address, value) {
    if (!this.isConnected) {
      throw new Error("未连接到PLC");
    }

    // 如果是单个值，转换为数组
    const values = Array.isArray(value) ? value : [value];

    try {
      return await this.client.writeSingleRegisterArray(address, values);
    } catch (err) {
      // 如果是连接错误，更新连接状态
      if (this._isConnectionError(err)) {
        this.isConnected = false;
      }
      throw err;
    }
  }
}

module.exports = ModbusCommunicationManager;
